package gui;

import information.Data;
import information.Date;
import information.Job;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Set;

import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import actions.ViewJobsAction;

/**
 * Creates a calendar panel that displays jobs to a Staff Member.
 * 
 * @author Natalie
 *
 */
@SuppressWarnings("serial")
public class CalendarPanel extends JPanel {
	
	/**
	 * Total width of Calendar. 
	 */
	private static final int CAL_WIDTH = 900;
	
	/**
	 * Height each row in the calendar. 
	 */
	private static final int ROW_HEIGHT = 100;
	
	/**
	 * Number of rows in the calendar. 
	 */
	private static final int ROW_NUM = 6;
	
	/**
	 * Number of columns in the calendar. 
	 */
	private static final int COL_NUM = 7;
	
	/**
	 * Labels for the heading of each column on the calendar. 
	 */
	private static final String[] DAYS = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
	
	/**
	 * Labels for the months. 
	 */
	private static final String[] MONTHS = {"January", "February", "March", "April", "May", "June", "July", "August", 
		"September", "October", "November", "December"};
	
	/**
	 * Label where the month will be displayed. 
	 */
	private JLabel myMonth;
	
	/**
	 * Number representing the current month being displayed. 
	 */
	private int myMonthNum;
	
	/**
	 * Current year being displayed by the calendar. 
	 */
	private int myYearNum;
	
	/**
	 * The previous button to move to the previous month on the calendar. 
	 */
	private JButton myPreviousButton;
	
	/**
	 * The next button to move to the next month on the calendar. 
	 */
	private JButton myNextButton;
	
	private JTable myCalendar;
	
	/**
	 * The model of the table that formats how the calendar should be displayed. 
	 */
	private CalendarTableModel myCalendarModel;
	
	/**
	 * The data that will be displayed by the calendar. 
	 */
	private Data myData;
	
	/**
	 * Creates a new calendar panel. Sets up all of the buttons and 
	 * displays the current month. 
	 * 
	 * @param theData The Data that will be displayed on the calendar. 
	 */
	public CalendarPanel(final Data theData) {
		super();
		setLayout(new BorderLayout());
		myData = theData;
		Calendar cal = Calendar.getInstance();
		myMonthNum = cal.get(Calendar.MONTH);
		myMonth = new JLabel(MONTHS[myMonthNum] + "  " + cal.get(Calendar.YEAR));
		myYearNum = cal.get(Calendar.YEAR);
		myPreviousButton = new JButton("<<");
		myNextButton = new JButton(">>");
		myCalendarModel = new CalendarTableModel(myData.getUserJobs());
		myCalendar = new JTable(myCalendarModel);
		start();
	}
	
	/**
	 * Sets up the controls and view of the calendar. 
	 */
	private void start() {
		setBorder(BorderFactory.createTitledBorder("Calendar - Current Pending Jobs: " + myData.getTotalJobsInQueue())); 
		JPanel topPanel = new JPanel(new BorderLayout());
		topPanel.add(myPreviousButton, BorderLayout.WEST);
		topPanel.add(myNextButton, BorderLayout.EAST);
		topPanel.add(myMonth, BorderLayout.CENTER);
		add(topPanel, BorderLayout.NORTH);
		myCalendar.setDefaultRenderer(CalendarPanel.class, new CustomCell());
		myCalendar.setDefaultEditor(CalendarPanel.class, new CustomCell());
		myNextButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent theEvent) {
				myMonthNum++;
				if(myMonthNum > 11) {
					myYearNum++;
					myMonthNum = 0;
				}
				refreshCalendar();
			}
		});
		myPreviousButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent theEvent) {
				myMonthNum--;
				if(myMonthNum < 0) {
					myYearNum--;
					myMonthNum = 11;
				}
				refreshCalendar();
			}
		});
		myCalendar.setPreferredScrollableViewportSize(new Dimension(CAL_WIDTH, ROW_NUM * ROW_HEIGHT));
		myCalendar.setRowHeight(ROW_HEIGHT);
		add(new JScrollPane(myCalendar), BorderLayout.CENTER);
		repaint();
	}
	
	/**
	 * Refreshes the calendar to a new month and year. 
	 * There is a bug in this method i didn't have time to work out. When a job is selected to view more 
	 * information and then you try to move to the next/previous month the cell doesn't refresh properly. 
	 */
	public void refreshCalendar() {
		remove(myCalendar);
		myMonth.setText(MONTHS[myMonthNum] + "  " + myYearNum);	
		myCalendarModel = new CalendarTableModel(myData.getUserJobs());
		myCalendar = new JTable(myCalendarModel);
		repaint();
	}
	
	
	/**
	 * The table model for the Calendar. Tells how the table should be displayed. 
	 * 
	 * @author Natalie
	 *
	 */
	private class CalendarTableModel extends AbstractTableModel {
		Set<Job> myJobs; 

		/**
		 * Creates a new calendar model with a set of all the jobs in the system. 
		 * @param theJobs The set of all jobs, past and current. 
		 */
		public CalendarTableModel(final Set<Job> theJobs) {
			myJobs = theJobs;
		}
		/**
		 * Returns CalendarPanel ad the class of each column in this table. 
		 * 
		 *
		 */
		//@requires this will only be called on type CalendarPanel.class
		public Class getColumnClass(int columnIndex) { return CalendarPanel.class; }
		public int getColumnCount() { return COL_NUM; }
		/**
		 * Returns the name of the day associated with the column passed in.  
		 */
		public String getColumnName(int columnIndex) { return DAYS[columnIndex]; }
		public int getRowCount() { return 6; }
		/**
		 * Returns the value at this index. It will return the day of the current month as 
		 * an integer. If the index is null, null will be returned.  
		 */
		public Object getValueAt(int rowIndex, int columnIndex) { 
			if (myJobs == null) {
				return null; 
			} else {
				GregorianCalendar calendar = new GregorianCalendar(myYearNum, myMonthNum, 1);
				int numOfDays = calendar.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
				int startingDay = calendar.get(GregorianCalendar.DAY_OF_WEEK);
				Integer day = (rowIndex - 1) * COL_NUM + startingDay + columnIndex - 1;
				if (day < 1 || day > numOfDays) return 0;	
				else return day;
			}
		}
		public boolean isCellEditable(int columnIndex, int rowIndex) { return true; }
	}

	/**
	 * A cell renderer and editor for every cell in the Calendar table. 
	 * 
	 * @author Natalie
	 *
	 */
	private class CustomCell extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {

		/**
		 * The panel to be displayed in the cell. 
		 */
		JPanel myPanel;
		/**
		 * The label where the date will be displayed in the cell. 
		 */
		JLabel myDate;

		/**
		 * Creates a new Custom cell with a blank date label and a box layout. 
		 */
		public CustomCell() {
			myDate = new JLabel();
			myPanel = new JPanel();
			myPanel.setLayout(new BoxLayout(myPanel, BoxLayout.Y_AXIS));
			myPanel.add(myDate);			
		}

		/**
		 * updateData will update the information in the cell to the passed in date. 
		 * 
		 * @param theDate Update cell to this date.  
		 * @param theTable The calendar table you want to update. 
		 * @param theisSelected Should be true. 
		 */
		private void updateData(Integer theDate, boolean theisSelected, JTable theTable) {
			myPanel.removeAll();
			if(theDate !=0){
				myDate.setText(theDate.toString());
				myPanel.add(myDate);
				Set<Job> jobSet = myData.getJobOnDay(new Date(myYearNum, myMonthNum + 1, theDate, 0, 0));
				for (Job job : jobSet) {
					myPanel.add(new JButton(new ViewJobsAction(job, job.getPark().getMyName(), myData.getCurrentUser())));
				}
			} else {
				myDate.setText(" ");
			}		
		}

		/**
		 * Overrides the default cell editor. Updates the table, and returns the tables panel.  
		 */
		public Component getTableCellEditorComponent(final JTable theTable, Object theValue,
				boolean theSelected, int theRow, int theColumn) {
			Integer date = (Integer)theValue;
			updateData(date, true, theTable);
			return myPanel;
		}

		public Object getCellEditorValue() {
			return null;
		}

		/**
		 * Overrides the default cell renderer. Updates the table, and returns the tables panel.  
		 */
		public Component getTableCellRendererComponent(JTable theTable, Object theValue,
				boolean theisSelected, boolean thehasFocus, int theRow, int theColumn) {
			Integer date = (Integer)theValue;
			updateData(date, theisSelected, theTable);
			return myPanel;
		}

	}
}



